﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Windows.Forms;

namespace Tzync
{
    /*****************************************************************************/
    /* Facade Class of our Software. Allocates responsibilities to other classes */
    /*****************************************************************************/

    public class SyncTool
    {
        //Data Members of the SyncTool Class
        private Analyze analyzer;
        private MetaData metaDataHandler;
        private List<Difference> differences;
        private List<TreeNode> arrNodes;
        private SystemType systemName;
        private bool secondTime, firstTime;
        private String rootAddress;
        private ISubject differenceSubject;
        private Rollback Roller;
        private String cpuID;
        private List<Difference> resolvedDifferenceList;


        public SyncTool()
        {
            arrNodes = new List<TreeNode>();
            firstTime = false;
            differenceSubject = new DifferenceSubject();
            Roller = new Rollback();
        }

        public List<Difference> GetDifferences()
        {
            return differences;
        }

        public bool GetFirstTime()
        {
            return firstTime;
        }

        public bool GetSecondTime()
        {
            return secondTime;
        }

        public List<TreeNode> GetArrNodes()
        {
            return this.arrNodes;
        }

        public ISubject GetDifferenceSubject()
        {
            return differenceSubject;
        }

        public void SetResolvedDifferenceList(List<Difference> newResolvedDifferenceList)
        {
            this.resolvedDifferenceList = newResolvedDifferenceList;
        }

        public List<Difference> GetResolvedDifferenceList()
        {
            return resolvedDifferenceList;
        }

        public void RegisterObserver(IObserver observer)
        {
            differenceSubject.RegisterObject(observer);     //register UI as an observerable object
        }

        public void Load(String address)
        {
            rootAddress = address;
            metaDataHandler = new MetaData(address, cpuID);
            systemName = metaDataHandler.readFromFile(ref secondTime, ref firstTime);
            arrNodes = metaDataHandler.getAllNodes();

            if (systemName == SystemType.Host)
            {
                if (arrNodes[0].getFullPathA().Length != 0 && rootAddress.CompareTo(arrNodes[0].getFullPathA()) != 0) throw new InvalidRootAddressException();
            }
            else if (systemName == SystemType.Guest)
            {
                if (secondTime==false && arrNodes[0].getFullPathB().Length != 0 && rootAddress.CompareTo(arrNodes[0].getFullPathB()) != 0) throw new InvalidRootAddressException();
            }
        }

        public void Analyze()
        {            
            DirectoryInfo D = new DirectoryInfo(@rootAddress);
            analyzer = new Analyze(arrNodes, secondTime, systemName, differenceSubject);
            
            try
            {
                differences = analyzer.findDiff(D, arrNodes[0]);
            }
            catch (InvalidPathException)
            {
                throw;
            }
            catch (ArgumentNullException)
            {
                throw;
            }
        }

        public SystemType GetSystemName()
        {
            return systemName;
        }

        public String GetRootAddress()
        {
            return rootAddress;
        }

        public String GetCpuID()
        {
            return cpuID;
        }

        public void SetCPUID(String str)
        {
            cpuID = str;
        }

        public void Sync()
        {
            //Roller.loadMetadata(arrNodes);
          
            if (firstTime)
            {
                DirectoryInfo source = new DirectoryInfo(rootAddress);
                Sync sync = new Sync(arrNodes, secondTime, systemName);
                sync.CopyFilesToHD(source);
            }
            else if (secondTime)
            {                                
                DirectoryInfo destination = new DirectoryInfo(rootAddress);
                Sync sync = new Sync(arrNodes, secondTime, systemName);
                rootAddress = sync.CopyFilesToSystem(destination);                
            }
            else
            {
                //Roller.reviewQueue(differences);
                //Roller.DeleteOld();
                //Roller.addRollbackFile(differences, arrNodes);
                //Roller.UpdateRollMeta();
                //Roller.backupRoll();
                Sync sync = new Sync(differences, arrNodes, systemName);
                sync.Reconcile();
            }
            metaDataHandler.writeToFile();
        }

        public Queue<RollbackFile> getRollbackFiles()
        {
             return Roller.returnRoll();
        }

        public void ExecuteRoll(List<string> PathList)
        {
            Roller.performRollback(PathList);
        }

        public List<RollbackFile> readRollMeta()
        {
            List<RollbackFile> newList = new List<RollbackFile>();
            string[] data;
            string line;
            char[] charSeparators = new char[] { ',' };
            int i = 0;
            if (File.Exists(@"C:\Tzync\Rollback\RollbackMeta"))
            {

                using (StreamReader readRoll = new StreamReader(@"C:\Tzync\Rollback\RollbackMeta"))
                {
                    line = readRoll.ReadLine();
                    while (line != null)
                    {
                        newList.Add(new RollbackFile());
                        data = line.Split(charSeparators);
                        newList[i].setPath(data[0]);
                        newList[i].setST(Convert.ToDateTime(data[1]));
                        newList[i].setid(Convert.ToInt32(data[2]));
                        i++;
                        line = readRoll.ReadLine();
                    
                    }
                    for (int j = 0; j < newList.Count(); j++)
                    {
                        if (systemName == SystemType.Host)
                        {
                            arrNodes[newList[j].getId()].getVersionA().First++;
                        }
                        else if (systemName == SystemType.Guest)
                        {
                            arrNodes[newList[j].getId()].getVersionB().Second++;
                        }
                    }

                }
            }
            return newList;

        }

        public void ResolveConflicts(List<Difference> conflicts)
        {
            Sync sync = new Sync(conflicts, arrNodes, systemName);
            sync.Reconcile();
            metaDataHandler.writeToFile();
        }

    }

    /***********************/
    /* Class SyncTool ends */
    /***********************/
}
